
#include <iostream>
#include <string>
#include "TCPServer.hpp"
#include "Protocol.hpp"
#include "CalCulate.hpp"
#include "Socket.hpp"

using namespace protocol_ns;

// 这里提供的服务是 对客户端的信息作反序列化，再将算出的结果反序列化并发送回客户端
// 算出结果的操作（处理数据的方式）由上层提供
using callback_t = std::function<Response(const Request &)>;

class Service
{
public:
    Service(callback_t callFunc)
        : _callFunc(callFunc)
    {
    }

    void ServiceHelper(socket_sptr sockptr, const InetAddr &client)
    {
        int sockfd = sockptr->SockFd();
        // 已经获取连接了，这里接收消息
        LOG(DEBUG, "get a new link, info [%s]:%d, fd : %d", client.IP().c_str(), client.Port(), sockfd);

        // 拼接一下客户端信息，方便查看
        std::string clientaddr = "[" + client.IP() + ":" + std::to_string(client.Port()) + "]";

        std::string buffer;
        while (true)
        {
            sleep(5);
            // 1. 接收客户端的信息
            int recvBytes = sockptr->Recv(&buffer);
            if (recvBytes < 0)
            {
                LOG(DEBUG, "client %s quit\n", clientaddr.c_str());
                break;
            }
            LOG(DEBUG, "server recv a protocol-----------------");
            std::cout << buffer << std::endl;
            // 2. 分析数据，得到完整报文（因为读取的数据中可能有多个报文，需要循环处理）
            std::string package;
            Request req;
            while (true)
            {
                // 将数据中的一个报文字符串提取出来,并将数据中的这个报文删除
                package = Decode(buffer);
                if (package.empty())
                    break;
                LOG(DEBUG, "server get a package-----------------");
                std::cout << package << std::endl;
                // 进行反序列化
                req.DeSerialize(package);
                // 处理数据
                Response res = _callFunc(req);
                // 将结果序列化
                std::string out;
                res.Serialize(&out);
                // 添加报头
                out = Encode(out);
                LOG(DEBUG, "server send a protocol to client-----------------");
                std::cout << out << std::endl;
                // 发送给客户端
                sockptr->Send(out);
            }
        }

        // 服务完毕，需要关闭套接字资源
        close(sockfd);
    }

private:
    callback_t _callFunc;
};

void Useage(const char *proc)
{
    printf("Useage error\n\t %s Port\n", proc);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Useage(argv[0]);
        return 1;
    }
    uint16_t port = std::stoi(argv[1]);

    CalCulate cal;
    // 将Service类中的_callFunc函数对象绑定为CalCulate类中的calculate成员函数
    Service cal_service(std::bind(&CalCulate::calculate, &cal, std::placeholders::_1));

    // 将TCPServer类中的_service函数对象绑定为Service类中的ServiceHelper成员函数
    io_service_t io_service = std::bind(&Service::ServiceHelper, &cal_service, std::placeholders::_1, std::placeholders::_2);

    std::unique_ptr<TCPServer> server = std::make_unique<TCPServer>(port, io_service);

    server->Loop();
    return 0;
}
